Package org.python.pydev.outline

Source Code of org.python.pydev.outline.OutlineLinkWithEditorAction

/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package org.python.pydev.outline;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.ListResourceBundle;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.ViewerFilter;
import org.python.pydev.core.bundle.ImageCache;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.IPyEditListener;
import org.python.pydev.editor.IPyEditListener2;
import org.python.pydev.editor.PyEdit;
import org.python.pydev.parser.visitors.scope.ASTEntryWithChildren;
import org.python.pydev.ui.UIConstants;


/**
* This action keeps the outline synched with the text selected in the text
* editor.
*
* Design notes:
* It's linked on the constructor and unlinked in the destructor.
*
* It considers that it's always linked, even if the action is inactive, but before executing it, a
* check is done to see if it's active or not.
*
* @author Fabio
*/
public class OutlineLinkWithEditorAction extends AbstractOutlineFilterAction implements IPyEditListener,
        IPyEditListener2 {

    private static final String PREF_LINK_WITH_EDITOR = "org.python.pydev.PREF_LINK_WITH_EDITOR";

    private WeakReference<PyEdit> pyEdit;

    public OutlineLinkWithEditorAction(PyOutlinePage page, ImageCache imageCache) {
        super("Link With Editor", page, imageCache, PREF_LINK_WITH_EDITOR, UIConstants.SYNC_WITH_EDITOR);

        pyEdit = new WeakReference<PyEdit>(page.editorView);
        relink();
    }

    /**
     * When called, it STOPS hearing notifications to update the outline when the cursor changes positions.
     */
    public void unlink() {
        PyEdit edit = pyEdit.get();
        if (edit != null) {
            edit.removePyeditListener(this);
        }
    }

    /**
     * When called, it STARTS hearing notifications to update the outline when the cursor changes positions.
     */
    public void relink() {
        PyEdit edit = pyEdit.get();
        if (edit != null) {
            edit.addPyeditListener(this);
        }
    }

    public void dispose() {
        unlink();
    }

    @Override
    protected ViewerFilter createFilter() {
        throw new RuntimeException(
                "Not implemented: as setActionEnabled is overriden, this action is not needed (as this is not a filter action).");
    }

    /**
     * Overridden to enable the linking with the editor instead of having a filter created.
     */
    @Override
    protected void setActionEnabled(boolean enableAction) {
        PyOutlinePage p = this.page.get();
        if (p != null) {
            p.getStore().setValue(PREF_LINK_WITH_EDITOR, enableAction);
            if (enableAction && pyEdit != null) {
                PyEdit edit = pyEdit.get();
                if (edit != null) {
                    handleCursorPositionChanged(edit, new PySelection(edit));
                }
            }
        }
    }

    public void onCreateActions(ListResourceBundle resources, PyEdit edit, IProgressMonitor monitor) {

    }

    public void onDispose(PyEdit edit, IProgressMonitor monitor) {

    }

    public void onSave(PyEdit edit, IProgressMonitor monitor) {

    }

    public void onSetDocument(IDocument document, PyEdit edit, IProgressMonitor monitor) {

    }

    /**
     * Hear mouse selections to update the selection in the outline
     */
    public void handleCursorPositionChanged(PyEdit edit, PySelection ps) {
        PyOutlinePage p = this.page.get();
        if (p != null && edit != null) {
            if (isChecked()) {
                doLinkOutlinePosition(edit, p, ps);
            }
        }
    }

    /**
     * Keeps the outline linked with the editor.
     */
    protected void doLinkOutlinePosition(PyEdit edit, PyOutlinePage p, PySelection ps) {
        ITextSelection t = ps.getTextSelection();
        IOutlineModel outlineModel = p.model;
        if (outlineModel != null) {
            StructuredSelection sel = getSelectionPosition(outlineModel.getRoot(), t);
            if (sel != null) {
                // we don't want to hear our own selections
                p.unlinkAll();
                try {
                    p.setSelection(sel);
                } finally {
                    p.relinkAll();
                }
            }
        }
    }

    /**
     * Convert the text selection to a model node in the outline (parsed item tree path).
     */
    private StructuredSelection getSelectionPosition(ParsedItem r, ITextSelection t) {
        try {
            ArrayList<ParsedItem> sel = new ArrayList<ParsedItem>();

            if (r != null) {
                do {
                    ParsedItem item = findSel(r, t.getStartLine() + 1);
                    if (item != null) {
                        sel.add(item);
                    }
                    r = item;
                } while (r != null);
            }
            TreePath treePath = null;
            if (sel != null && sel.size() > 0) {
                treePath = new TreePath(sel.toArray());
            }
            if (treePath != null) {
                return new TreeSelection(treePath);
            }
        } catch (Exception e) {
            Log.log(e);
        }
        return null;
    }

    /**
     * @return The parsed item that should be selected given the startLine passed.
     */
    private ParsedItem findSel(ParsedItem r, int startLine) {
        ParsedItem prev = null;

        ParsedItem[] children = r.getChildren();
        if (children != null) {
            for (ParsedItem i : children) {
                ASTEntryWithChildren astThis = i.getAstThis();
                if (astThis != null && astThis.node != null) {
                    if (astThis.node.beginLine == startLine) {
                        prev = i;
                        break;
                    }
                    if (astThis.node.beginLine > startLine) {
                        break;
                    }
                }
                prev = i;
            }
        }
        return prev;
    }

}
TOP

Related Classes of org.python.pydev.outline.OutlineLinkWithEditorAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.